package com.dddframework.core.utils;

import cn.hutool.core.util.StrUtil;
import com.dddframework.core.contract.IR;
import com.dddframework.core.contract.enums.ResultCode;
import com.dddframework.core.contract.exception.ServiceException;

import java.util.function.Supplier;

/**
 * 业务断言类，断言不通过将抛出ServiceException
 */
public class BizAssert {
    /**
     * 断言是否为真，如果为 {@code false} 抛出给定的异常<br>
     *
     * <pre class="code">
     * Assert.isTrue(i &gt; 0, ServiceException::new);
     * </pre>
     *
     * @param <X>        异常类型
     * @param expression 布尔值
     * @param supplier   指定断言不通过时抛出的异常
     * @throws X if expression is {@code false}
     */
    public static <X extends Throwable> void isTrue(Boolean expression, Supplier<? extends X> supplier) throws X {
        if (!expression) {
            throw supplier.get();
        }
    }

    /**
     * 断言是否为假，如果为 {@code true} 抛出给定的异常<br>
     *
     * <pre class="code">
     * Assert.isFalse(i &gt; 0, ServiceException::new);
     * </pre>
     *
     * @param <X>        异常类型
     * @param expression 布尔值
     * @param supplier   指定断言不通过时抛出的异常
     * @throws X if expression is {@code true}
     */
    public static <X extends Throwable> void isFalse(Boolean expression, Supplier<? extends X> supplier) throws X {
        if (expression) {
            throw supplier.get();
        }
    }

    public static void isTrue(Boolean expression, Integer code, String errorMsg, Object... params) {
        if (!expression) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
    }

    public static void isTrue(Boolean expression, String errorMsg, Object... params) {
        if (!expression) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
    }

    public static void isFalse(Boolean expression, Integer code, String errorMsg, Object... params) {
        if (expression) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
    }

    public static void isFalse(Boolean expression, String errorMsg, Object... params) {
        if (expression) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
    }

    public static <T> T notNull(T object, Integer code, String errorMsg, Object... params) {
        if (object == null) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
        return object;
    }

    public static <T> T notNull(T object, String errorMsg, Object... params) {
        if (object == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
        return object;
    }

    public static <T> T notNull(T object) {
        if (object == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this object must not be null");
        }
        return object;
    }

    public static void notBlank(String string, Integer code, String errorMsg, Object... params) {
        if (string == null || string.length() == 0) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
    }

    public static void notBlank(String string, String errorMsg, Object... params) {
        if (string == null || string.length() == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
    }

    public static void notBlank(String string) {
        if (string == null || string.length() == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this string must not be null or blank");
        }
    }

    public static <E, T extends Iterable<E>> T notEmpty(T collection, Integer code, String errorMsg, Object... params) {
        if (collection == null || !collection.iterator().hasNext()) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
        return collection;
    }

    public static <E, T extends Iterable<E>> T notEmpty(T collection, String errorMsg, Object... params) {
        if (collection == null || !collection.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
        return collection;
    }

    public static <E, T extends Iterable<E>> T notEmpty(T collection) {
        if (collection == null || !collection.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this collection must not be null or empty");
        }
        return collection;
    }

    public static <E, T extends Iterable<E>> T isEmpty(T collection, Integer code, String errorMsg, Object... params) {
        if (collection != null && collection.iterator().hasNext()) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
        return collection;
    }

    public static <E, T extends Iterable<E>> T isEmpty(T collection, String errorMsg, Object... params) {
        if (collection != null && collection.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
        return collection;
    }

    public static <E, T extends Iterable<E>> T isEmpty(T collection) {
        if (collection != null && collection.iterator().hasNext()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this collection must not be null or empty");
        }
        return collection;
    }

    public static <T> T[] notEmpty(T[] objects, Integer code, String errorMsg, Object... params) {
        if (objects == null || objects.length == 0) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
        return objects;
    }

    public static <T> T[] notEmpty(T[] objects, String errorMsg, Object... params) {
        if (objects == null || objects.length == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
        return objects;
    }

    public static <T> T[] notEmpty(T[] arrays) {
        if (arrays == null || arrays.length == 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this arrays must not be null or empty");
        }
        return arrays;
    }

    public static <T> T[] isEmpty(T[] arrays, Integer code, String errorMsg, Object... params) {
        if (arrays != null && arrays.length != 0) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
        return arrays;
    }

    public static <T> T[] isEmpty(T[] arrays, String errorMsg, Object... params) {
        if (arrays != null && arrays.length != 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
        return arrays;
    }

    public static <T> T[] isEmpty(T[] arrays) {
        if (arrays != null && arrays.length != 0) {
            throw new ServiceException(ResultCode.FAIL.getCode(), "this arrays must be null or empty");
        }
        return arrays;
    }

    public static <T> T isOk(IR r, Integer code, String errorMsg, Object... params) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
        return r.getData();
    }

    public static <T> T isOk(IR r, String errorMsg, Object... params) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
        return r.getData();
    }

    public static <T> T isOk(IR r, Supplier<String> supplier) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), supplier.get());
        }
        return r.getData();
    }

    public static <T> T isOk(IR r) {
        if (r == null || !r.isOk()) {
            throw new ServiceException(ResultCode.FAIL.getCode(), r == null ? "this result must not be null" : r.getMsg());
        }
        return r.getData();
    }

    public static <T> T notNull(IR r, Integer code, String errorMsg, Object... params) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(code, StrUtil.format(errorMsg, params));
        }
        return r.getData();
    }

    public static <T> T notNull(IR r, String errorMsg, Object... params) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), StrUtil.format(errorMsg, params));
        }
        return r.getData();
    }

    public static <T> T notNull(IR r, Supplier<String> supplier) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), supplier.get());
        }
        return r.getData();
    }

    public static <T> T notNull(IR r) {
        if (r == null || !r.isOk() || r.getData() == null) {
            throw new ServiceException(ResultCode.FAIL.getCode(), r == null ? "this result must not be null" : r.getMsg());
        }
        return r.getData();
    }

}
